/* UTF8 Encoding */
/*-----------------------------------------------------------------------
|                            FILE DESCRIPTION                           |
-----------------------------------------------------------------------*/
/*----------------------------------------------------------------------
  - File name     : at_base.h
  - Author        : liuzhihua (liuzhihuawy@163.com)
  - Update date   : 2024.08.17
  -	Brief         : at cmd base
  - Version       : v0.1
-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------
|                               UPDATE NOTE                             |
-----------------------------------------------------------------------*/
/**
  * Update note:
  * ------------   ---------------   ----------------------------------
  *     Date            Author                      Note
  * ------------   ---------------   ----------------------------------
  *  2024.08.17       liuzhihua                 Create file          
***/

#ifndef __AT_BASE_H__
#define __AT_BASE_H__

/*-----------------------------------------------------------------------
|                               INCLUDES                                |
-----------------------------------------------------------------------*/
#include <stdint.h>
#include <stddef.h>

/*-----------------------------------------------------------------------
|                                DEFINES                                |
-----------------------------------------------------------------------*/
#define AT_BASE_ASSERT(x)  if(!(x)) { while(1); }

/*-----------------------------------------------------------------------
|                                 CLASS                                 |
-----------------------------------------------------------------------*/


class ATBase
{
    public:
        ATBase(void);
        // ~ATBase();
        static const uint16_t CMD_STRING_MAX_LENGTH = 256;
        static const uint16_t RX_BUFF_MAX_LENGTH = 256;
        static const uint8_t CMD_RETRY_MAX_TIMES = 0xFF^0xC0;
        static const uint8_t CMD_RETRY_INFINITE = CMD_RETRY_MAX_TIMES;
        enum {
            CMD_STATE_IDLE = 0, // cmd idle
            CMD_STATE_WAIT = 1, // cmd wait
            CMD_STATE_SEND = 2, // cmd send
            CMD_STATE_FAILED = 3, // cmd failed
        };
        typedef struct at_cmd_typedef
        {
            const char *reply;    // [1]reply string to match (only const char)
            // [2] event handle function
            int (*event_handle_fn)(void * object,
                                   const struct at_cmd_typedef *pCmd,
                                   uint32_t events);
            uint8_t  __state:2;   // cmd state
            uint8_t  retry:6;     // [3]cmd retry times
            uint8_t  id;          // [4]cmd id
            uint16_t timeout;     // [5]cmd timeout (ms)
            uint16_t expect_size; // [6]expect size to receive
            uint16_t cmd_size;    // [7]cmd string size
            char cmd[ATBase::CMD_STRING_MAX_LENGTH]; // [8]cmd string
            struct at_cmd_typedef *__next;
        } at_cmd_t;

        typedef enum
        {
            EVENT_TIMEOUT = 1 << 0,  // cmd timeout
            EVENT_RECV    = 1 << 1,  // receive data
            EVENT_FULLED  = 1 << 2,  // rx buffer is full
            EVENT_MATCH   = 1 << 3,  // rx buffer match reply
            EVENT_CMDEND  = 1 << 4,  // cmd end
            EVENT_FAILED  = 1 << 5,  // cmd failed
        } event_def;

        typedef enum
        {
            ERROR_BUFFER_OVERFLOW = 1,
            ERROR_INVALID_PARAM = 1 << 1,
            ERROR_INVALID_QUEUE = 1 << 2,
        } error_def;

    private:
        at_cmd_t *pCurCmd;  // current cmd
        at_cmd_t *pTailCmd; // tail cmd
        at_cmd_t *pIdleCmd; // idle cmd list
        uint16_t cmdCnt;
        uint16_t idleCmdCnt;
        uint32_t time;
        char formatBuffer[CMD_STRING_MAX_LENGTH];
        bool insert(at_cmd_t *cmd, uint16_t pos);
        at_cmd_t * remove(uint16_t pos);
        void insert_idle_list(at_cmd_t *cmd);
    public:
        void * arg;
        uint32_t errors;
        uint8_t rxData[RX_BUFF_MAX_LENGTH];
        uint16_t rxSize;
        uint8_t retry; // cmd retry times
        int receive_callback(const uint8_t *rxdata, uint16_t size);
        int receive_callback(const char *rxdata);
        int tick(uint32_t timeMs);
        bool push(at_cmd_t *pCmd, ...);
        bool push(uint16_t pos, at_cmd_t *pCmd, ...);
        int next(void);
        void clear(void);
        bool clear(uint8_t id);
        at_cmd_t * get_cmd(void);
        at_cmd_t * push_idle_cmd(at_cmd_t *cmd);
        at_cmd_t * pop_idle_cmd(void);
        int get_cmd_id(void);
        int get_cmd_num(void);
        int get_idle_cmd_num(void);
        static uint8_t *data_find_sub(const uint8_t *pdata,
                                      size_t size,
                                      const uint8_t *subdata,
                                      uint8_t subdatasize);
    protected:
        virtual int cmd_send(const uint8_t *txdata, uint16_t size) = 0;
};


#ifdef  __cplusplus
    extern "C" {
#endif

#ifdef __cplusplus
	}
#endif
#endif
